package yf.mall.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.yf.common.SdkResult;
import com.yf.entity.WxConfigEntity;
import com.yf.jssdk.SdkApi;
import com.yf.service.WxConfigService;
import com.yf.service.WxPayService;
import com.yf.utils.DateUtil;
import com.yf.utils.ShiroUtils;
import org.apache.catalina.User;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import yf.mall.common.Const;
import yf.mall.dao.*;
import yf.mall.entity.*;
import com.yf.service.impl.BaseServiceImpl;
import yf.mall.enums.*;
import com.yf.response.RRException;
import yf.mall.service.*;
import yf.mall.vo.*;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.text.SimpleDateFormat;

import java.util.*;

import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.crypto.IllegalBlockSizeException;

/**
 * 账户Service实现类
 *
 * @author hxf
 * @email 505860922@qq.com
 * @date Mon Aug 26 16:58:11 CST 2019
 */
@Service
public class AccountServiceImpl extends BaseServiceImpl<AccountEntity> implements AccountService {

    private AccountDao accountDao;

    @Autowired
    private UserDao userDao;

    @Resource
    @Lazy
    private UserService userService;

    @Resource
    @Lazy
    private LevelService levelService;


    @Autowired
    public void setDao(AccountDao accountDao) {
        this.accountDao = accountDao;
        super.setBaseDao(accountDao);
    }

    /**
     * 计算订单中非代理有利金额
     *
     * @param orderEntity
     * @param userEntity
     */
    private void sumNoAgentExp(MallOrderEntity orderEntity, UserEntity userEntity) {
        List<OrderItemEntity> itemEntities = this.orderItemDao.findByOrderId(orderEntity.getId());
        UserEntity topUser = this.userDao.get(userEntity.getPid());
        BigDecimal total = BigDecimal.ZERO;
        if (orderEntity != null && itemEntities != null && itemEntities.size() > 0) {
            for (OrderItemEntity orderItemEntity : itemEntities) {
                MallGoodsEntity mallGoodsEntity = mallGoodsDao.get(orderItemEntity.getGoodsId());
                StoresEntity stores = storesService.findByUserId(userEntity.getId());
                if (!mallGoodsEntity.getSaleType().equals(MallGoodsSaleTypeEnum.AGENT.getIndex())&&!mallGoodsEntity.getSaleType().equals(MallGoodsSaleTypeEnum.DAY_SEL.getIndex())) {
                    if (mallGoodsEntity.getSaleType().equals(MallGoodsSaleTypeEnum.STORES.getIndex()) && stores != null) {
                        total = total.add(mallGoodsEntity.getShopPrice().multiply(new BigDecimal(orderItemEntity.getQuantity())));
                    } else {
                        total = total.add(mallGoodsEntity.getNowPrice().multiply(new BigDecimal(orderItemEntity.getQuantity())));
                    }
                }
            }
        }
        rewardExp(topUser.getId(), total, orderEntity.getOrderNo(), userEntity.getName(), true);
    }

    @Autowired
    private StoresService storesService;

    @Autowired
    private MallGoodsDao mallGoodsDao;


    /**内部方法**/


    /**
     * 外部方法实现
     **/

    @Autowired
    private AccountRecordDao accountRecordDao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void transfer(Long fromUserId, Long toUserId, int type, BigDecimal amount, String remark) {

        if(amount==null||amount.compareTo(BigDecimal.ZERO)<=0){
            return;
        }

        if (!fromUserId.equals(Const.ADMIN_ID) && fromUserId.equals(toUserId)) {
            throw new RRException("禁止转给自己");
        }

        //TODO 转经验值比较特殊
        if (type == AccountTypeEnum.EXP.getIndex()) {
            transferExp(fromUserId, toUserId, amount, remark);
            return;
        }

//        AccountEntity fromUserAccount = decrease(fromUserId, type, amount);
//        AccountEntity toUserAccount = increase(toUserId, type, amount);
        //生成记录
        AccountRecordEntity recordEntity = new AccountRecordEntity(fromUserId, toUserId, type, amount, null, null, new Date(), remark, AccountRecordStatusEnum.DONE.getIndex(), AccountRecordBusEnum.TRANSFER.getIndex());
        //转账
        if (remark!=null&&remark.contains("素材id")) {
            remark = "用户发布爆款素材审核通过赠送优惠券";
            AccountRecordEntity record = new AccountRecordEntity(fromUserId, toUserId, type, amount, null, null, new Date(), remark, AccountRecordStatusEnum.DONE.getIndex(), AccountRecordBusEnum.TRANSFER.getIndex());
            doneTransfer(record);
        } else {
            doneTransfer(recordEntity);
        }

        accountRecordDao.save(recordEntity);
        //通知
//        noticeAccount(recordEntity);
    }


    @Override
    public void pay(Long userId, int type, BigDecimal amount, String orderNo) {
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            return;
        }
        AccountEntity userAccount = decrease(userId, type, amount);
        UserEntity userEntity = userDao.get(userId);
        String remark = userEntity.getName() + Const.BUY_ORDER_NO + orderNo;
        AccountRecordEntity recordEntity = null;
        recordEntity = new AccountRecordEntity(userId, Const.ADMIN_ID, type, amount, userAccount.getAmount(), null, new Date(), remark, AccountRecordStatusEnum.DONE.getIndex(), AccountRecordBusEnum.PAY.getIndex());

        accountRecordDao.save(recordEntity);
        //通知
        noticeAccount(recordEntity);
    }


    @Override
    public void autoPay(Long userId, int type, BigDecimal amount, String orderNo) {
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            return;
        }
        AccountEntity userAccount = decrease(userId, type, amount);
        UserEntity userEntity = userDao.get(userId);
        String remark = userEntity.getName() + Const.AUTO_BUY_ORDER_NO + orderNo;
        AccountRecordEntity recordEntity = new AccountRecordEntity(userId, Const.ADMIN_ID, type, amount, userAccount.getAmount(), null, new Date(), remark, AccountRecordStatusEnum.DONE.getIndex(), AccountRecordBusEnum.AUTO_PAY.getIndex());
        accountRecordDao.save(recordEntity);
        //通知
        noticeAccount(recordEntity);
    }

    /**
     * 是否立即到账
     *
     * @param userId
     * @param amount
     * @param orderNo
     * @param name
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void rewardExp(Long userId, BigDecimal amount, String orderNo, String name, boolean reward) {
        //最搞可以升级的级别
//        LevelEntity levelEntity = levelDao.findBaseMax();
//        AccountEntity accountEntity = findByUserIdAndType(userId,AccountTypeEnum.EXP.getIndex());
//        //经验值增长超过限度
//        if(amount.add(accountEntity.getAmount()).compareTo(levelEntity.getAmount())>0 ){
//            //最多能送的
//            amount  = levelEntity.getAmount().subtract(accountEntity.getAmount());
//        }
        LevelEntity levelEntity = levelService.findByUserId(userId);
        AccountEntity accountEntity = findByUserIdAndType(userId, AccountTypeEnum.EXP.getIndex());
        //实际经验值比我等级的经验值少 补上
        if (accountEntity.getAmount().compareTo(levelEntity.getAmount()) < 0) {
            reward(userId, AccountTypeEnum.EXP.getIndex(), levelEntity.getAmount().subtract(accountEntity.getAmount()), name, "", reward, AccountRecordBusEnum.TRANSFER.getIndex());
        }
        reward(userId, AccountTypeEnum.EXP.getIndex(), amount, name, orderNo, reward, AccountRecordBusEnum.TRANSFER.getIndex());
        if (reward) { //立即到账 TODO  收款经验的时候也要执行此操作
            //送完以后判断能否升级
            accountEntity = findByUserIdAndType(userId, AccountTypeEnum.EXP.getIndex());
            levelService.changeLevelByExp(userId, accountEntity.getAmount());
        }
    }

    @Override
    public void rewardEqlExp(Long userId, BigDecimal amount, String orderNo, String name, boolean reward) {
        UserEntity user = userDao.get(userId);
        LevelEntity level = levelDao.get(user.getLevelId());
        int idx = 0;
        UserEntity parent = userDao.get(user.getPid());
        while (!parent.getId().equals(Const.ADMIN_ID)){
            idx ++;
            if(idx>50){
                throw new RuntimeException("上下级循环");
            }
            LevelEntity parentLevel = levelDao.get(parent.getLevelId());
            if(level.getLv().equals(parentLevel.getLv())){//平级就送
                rewardExp(parent.getId(),amount,orderNo,name,reward);
            }else if (parentLevel.getLv()<level.getLv()){ //遇到高级别的 截断
                break;
            }
            parent = userDao.get(parent.getPid());
        }
//        给上级非代理有利利润
//        MallOrderEntity orderEntity  = mallOrderDao.findByOrderNo(orderNo);
//        sumNoAgentExp(orderEntity,user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void backExp(Long userId, BigDecimal amount, String orderNo, String name) {
        String remark = name + Const.BACK_ORDER_NO + orderNo;
        AccountRecordEntity recordEntity = new AccountRecordEntity(userId, Const.ADMIN_ID, AccountTypeEnum.EXP.getIndex(), amount, null, null, new Date(), remark, AccountRecordStatusEnum.DONE.getIndex(), AccountRecordBusEnum.BACK.getIndex());
        accountRecordDao.save(recordEntity);
        doneTransfer(recordEntity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void transferExp(Long fromUserId, Long toUserId, BigDecimal amount, String remark) {
       /* Long userId = toUserId;
        Boolean flag = false;
        int num = 0;
        while (true){
            num++;
            if (num > 30){
                throw new RRException("级别层次关系错误");
            }
            UserEntity userEntity = userDao.get(userId);
            //如果上级是公司直接结束循坏
            if (userEntity.getPid().equals(Const.ADMIN_ID)){
                break;
            }
            //如果上级不是fromUser 则循坏查找是否属于fromUser团队
            if (userEntity.getPid().equals(fromUserId)){
                flag = true;
                break;
            }
            userId = userEntity.getPid();
        }
        if (!flag){
            throw new RRException("经验值只能转给团队以内的下级");
        }*/
        LevelEntity fromUserLevel = levelDao.findByUserId(fromUserId);
        LevelEntity toUserLevel = levelDao.findByUserId(toUserId);
        if (fromUserLevel.getLv() == toUserLevel.getLv() && fromUserId != Const.ADMIN_ID && toUserId != Const.ADMIN_ID) {
            throw new RRException("您不能转给同级");
        }
        LevelEntity vipBase = levelDao.findVipBase();
        AccountEntity toUserAccount = findByUserIdAndType(toUserId, AccountTypeEnum.EXP.getIndex());
        AccountEntity fromUserAccount = findByUserIdAndType(fromUserId, AccountTypeEnum.EXP.getIndex());
        if (!fromUserId.equals(Const.ADMIN_ID)) { //代理级别与经验值不匹配
            if (fromUserAccount.getAmount().compareTo(fromUserLevel.getAmount()) < 0) {
                fromUserAccount.setAmount(fromUserLevel.getAmount());
                update(fromUserAccount);
            }
        }
        if (!toUserId.equals(Const.ADMIN_ID)) { //代理级别与经验值不匹配
            if (toUserAccount.getAmount().compareTo(toUserLevel.getAmount()) < 0) {
                LevelEntity toLevel = this.levelDao.findByUserId(toUserId);
                toUserAccount.setAmount(toUserAccount.getAmount().add(toLevel.getAmount()));
                update(toUserAccount);
            }
        }
        //高级别转给低级别 增加低级别的  如果不是公司转出 不能高于大区的级别的经验值且不能高于自己的
        if ((fromUserLevel.getLv() < toUserLevel.getLv() || fromUserId.equals(Const.ADMIN_ID)) && !toUserId.equals(Const.ADMIN_ID)) {
            //非公司转出限制数量
            if (!fromUserId.equals(Const.ADMIN_ID)) {
                //接收人的经验值 不能转出超过大区 且不能超过自己的
                if (fromUserLevel.getAmount().compareTo(toUserAccount.getAmount().add(amount)) <= 0) {
                    throw new RRException("经验值已不能给下级增加");
                }
            }
            //增加到账人的
            toUserAccount = increase(toUserId, AccountTypeEnum.EXP.getIndex(), amount);
            levelService.changeLevelByExp(toUserId, toUserAccount.getAmount());

        }
        //低级别转给高级别 或者转给公司/上级
        else if (fromUserLevel.getLv() > toUserLevel.getLv() || toUserId.equals(Const.ADMIN_ID)) {
            //当前经验值小于本身的经验值 补齐
            if (fromUserAccount.getAmount().compareTo(amount) < 0) {
                throw new RRException("退回经验值超过限制");
            }
            fromUserAccount = decrease(fromUserId, AccountTypeEnum.EXP.getIndex(), amount);
            levelService.changeLevelByExp(fromUserId, fromUserAccount.getAmount());
        }
        //生成记录 通知
        AccountRecordEntity recordEntity = new AccountRecordEntity(fromUserId, toUserId, AccountTypeEnum.EXP.getIndex(), amount, fromUserAccount.getAmount(), toUserAccount.getAmount(), new Date(), "经验值调配", AccountRecordStatusEnum.DONE.getIndex(), AccountRecordBusEnum.TRANSFER.getIndex());
        accountRecordDao.save(recordEntity);
        noticeAccount(recordEntity);
    }

    /**
     * 返还钱
     *
     * @param userId
     * @param type
     * @param amount
     * @param orderNo
     */
    @Transactional(rollbackFor = Exception.class)
    public void returnMoney(Long userId, int type, BigDecimal amount, String orderNo) {
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            return;
        }
        AccountEntity userAccount = increase(userId, type, amount);
        UserEntity userEntity = userDao.get(userId);
        String remark = userEntity.getName() + Const.BACK_ORDER_NO + orderNo;
        AccountRecordEntity recordEntity = new AccountRecordEntity(Const.ADMIN_ID, userId, type, amount, userAccount.getAmount(), null, new Date(), remark, AccountRecordStatusEnum.DONE.getIndex(), AccountRecordBusEnum.BACK.getIndex());
        accountRecordDao.save(recordEntity);
        //通知
        noticeAccount(recordEntity);
    }

    @Override
    public AccountRecordEntity reward(Long userId, int type, BigDecimal amount, String name, String orderNo, Boolean isReward, Integer busType) {
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            return null;
        }
        Integer bus = busType;
        String remark = name + Const.BUY_ORDER_NO + orderNo;
        AccountRecordEntity recordEntity = buildAwaitTransfer(userId, type, amount, remark, bus);
        //立即给与
        if (isReward) {
            if(recordEntity.getType().equals(AccountTypeEnum.CASH.getIndex())&&recordEntity.getBus().equals(AccountRecordBusEnum.SHARE_REWARD.getIndex())){
                //微信直接返利了
                wxTransfer(recordEntity);
            }else {
                doneTransfer(recordEntity);
            }

        } else {
            if(type!=AccountTypeEnum.EXP.getIndex()){//经验值不通知
                //通知
                noticeAccount(recordEntity);
            }
        }
        return recordEntity;
    }

    @Override
    public void rewardRegister(Long userId) {
        BigDecimal amount = new BigDecimal(100);
        Integer bus = AccountRecordBusEnum.TRANSFER.getIndex();
        String remark = "新用户完善信息奖励";
        AccountRecordEntity recordEntity = buildAwaitTransfer(userId, AccountTypeEnum.COUPON.getIndex(), amount, remark, bus);
        doneTransfer(recordEntity);
        //给上级送
        UserEntity userEntity = userDao.get(userId);
        if (userEntity.getPid().equals(Const.ADMIN_ID)) {
            return;
        }
        amount = new BigDecimal(20);
        bus = AccountRecordBusEnum.TRANSFER.getIndex();
        remark = userEntity.getName() + "完善信息奖励";
        recordEntity = buildAwaitTransfer(userEntity.getPid(), AccountTypeEnum.COUPON.getIndex(), amount, remark, bus);
        doneTransfer(recordEntity);
    }

    @Override
    public void shopProfit(Long shopId, BigDecimal money, String name, String orderNo) {
        if (money.compareTo(BigDecimal.ZERO) <= 0 || shopId.equals(Const.ADMIN_ID)) {
            return;
        }
        Integer bus = AccountRecordBusEnum.SHOP.getIndex();
        String remark = name + Const.BUY_ORDER_NO + orderNo;
        AccountRecordEntity recordEntity = buildAwaitTransfer(shopId, AccountTypeEnum.CASH.getIndex(), money, remark, bus);
        //通知
        noticeAccount(recordEntity);
    }

    @Autowired
    private ShopService shopService;

    @Override
    public void shopManager(Long shopId, BigDecimal money, String name, String orderNo) {
        if (money.compareTo(BigDecimal.ZERO) <= 0 || shopId.equals(Const.ADMIN_ID)) {
            return;
        }
        ShopEntity shopEntity = shopService.findByUserId(shopId);
        if (shopEntity == null) return;
        if (shopEntity.getMid() == null) return;
        Integer bus = AccountRecordBusEnum.SHOP_MANAGER_REWARD.getIndex();
        String remark = name + Const.BUY_ORDER_NO + orderNo;
        AccountRecordEntity recordEntity = buildAwaitTransfer(shopEntity.getMid(), AccountTypeEnum.CASH.getIndex(), money, remark, bus);
        //通知
        noticeAccount(recordEntity);
    }

    /**
     * 公司给出的可以延迟到账
     *
     * @param userId
     * @param type
     * @param amount
     * @param remark
     * @return
     */
    private AccountRecordEntity buildAwaitTransfer(Long userId, int type, BigDecimal amount, String remark, int bus) {
        Long fromUserId = Const.ADMIN_ID;
        //生成记录
        AccountRecordEntity recordEntity = new AccountRecordEntity(fromUserId, userId, type, amount, null, null, new Date(), remark, AccountRecordStatusEnum.WAIT.getIndex(), bus);
        accountRecordDao.save(recordEntity);
        return recordEntity;
    }


    @Transactional(rollbackFor = Exception.class)
    public void back(Long id) {
        AccountRecordEntity recordEntity = accountRecordDao.get(id);
        //生成记录
        String remark = recordEntity.getInfo().replace(Const.BUY_ORDER_NO, Const.BACK_ORDER_NO);
        //未完成直接删除
        if (recordEntity.getStatus().equals(AccountRecordStatusEnum.WAIT.getIndex())) {
            accountRecordDao.delete(id);
            noticeDeleteAccount(recordEntity);
            return;
        }
        //已经完成的
        if (recordEntity.getStatus().equals(AccountRecordStatusEnum.DONE.getIndex())) {
            BigDecimal toUserAmount = null;
            BigDecimal fromUserAmount = null;
            if (!recordEntity.getToUserId().equals(Const.ADMIN_ID)) {
                AccountEntity userAccount = decrease(recordEntity.getToUserId(), recordEntity.getType(), recordEntity.getAmount());
                toUserAmount = userAccount.getAmount();
            }
            if (!recordEntity.getFromUserId().equals(Const.ADMIN_ID)) {
                AccountEntity userAccount = increase(recordEntity.getFromUserId(), recordEntity.getType(), recordEntity.getAmount());
                fromUserAmount = userAccount.getAmount();

            }

            AccountRecordEntity recordEntity1 = new AccountRecordEntity(recordEntity.getToUserId(), recordEntity.getFromUserId(), recordEntity.getType(), recordEntity.getAmount(), toUserAmount, fromUserAmount, new Date(), remark, AccountRecordStatusEnum.DONE.getIndex(), recordEntity.getBus());
            accountRecordDao.save(recordEntity1);
            recordEntity1.setInfo(remark);
            //如果是退回经验值 还要改变级别
            if (recordEntity.getType() == AccountTypeEnum.EXP.getIndex() && recordEntity.getToUserId() != Const.ADMIN_ID) {
                levelService.changeLevelByExp(recordEntity1.getFromUserId(), toUserAmount);
            }
            //通知
            noticeAccount(recordEntity1);
        }
    }

    private void noticeDeleteAccount(AccountRecordEntity recordEntity) {
        setScale(recordEntity);
        UserEntity toUser = userDao.get(recordEntity.getToUserId());
        noticeService.sendAccount(toUser.getOpenId(), "-" + recordEntity.getAmount(), recordEntity.getToNowAmount(), AccountTypeEnum.indexOf(recordEntity.getType()),
                recordEntity.getInfo() + AccountRecordTypeEnum.indexOf(recordEntity.getType()) + recordEntity.getAmount());

    }

    @Resource
    @Lazy
    private MallOrderService mallOrderService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancel(String orderNo) {
        List<AccountRecordEntity> records = new ArrayList<>();

        //所有支付出去的券
        List<AccountRecordEntity> recordPay = accountRecordDao.findBusPay(orderNo);

        records.addAll(recordPay);
        //所有奖励的券
        List<AccountRecordEntity> recordReward = findByOrderNoAndBusType(orderNo, AccountRecordBusEnum.SHOP.getIndex(), AccountRecordBusEnum.SHOP_MANAGER_REWARD.getIndex(), AccountRecordBusEnum.SHARE_REWARD.getIndex(), AccountRecordBusEnum.AREA_REWARD.getIndex(),AccountRecordBusEnum.LEVEL_PROFIT.getIndex());
        //所有奖励的经验值
        List<AccountRecordEntity> recordExp = this.accountRecordDao.findByTypeAndBus(orderNo, AccountRecordTypeEnum.EXP.getIndex(), AccountRecordBusEnum.TRANSFER.getIndex());
        records.addAll(recordExp);
        records.addAll(recordReward);
        //所有货款
        List<AccountRecordEntity> recordCod = findByOrderNoAndBusType(orderNo, AccountRecordBusEnum.PAYMENT.getIndex());
        records.addAll(recordCod);
        //执行退还
        records.forEach(record -> {
            back(record.getId());
        });
        //如果是其它支付 转换成代金券退回
        MallOrderEntity orderEntity = mallOrderService.findByOrderNo(orderNo);
        //进货
        if (orderEntity.getBusType() == MallOrderBusTypeEnum.BUY.getIndex() && orderEntity.getPayStatus() == MallOrderPayStatusEnum.PAID.getIndex() && MallOrderPayWayEnum.WX.getIndex() == orderEntity.getPayWay()) {
            //有钱可以退
            if (mallOrderService.getRetailPrice(orderEntity).compareTo(BigDecimal.ZERO) > 0) {
                returnMoney(orderEntity.getUserId(), AccountTypeEnum.CASH.getIndex(), mallOrderService.getRetailPrice(orderEntity), orderNo);
            }
        }
    }


    /**
     * 完成一个订单相关的所有转账
     *
     * @param orderNo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doneTransfer(String orderNo) {
        List<AccountRecordEntity> accountRecordEntities = this.accountRecordDao.findByOrderNos("%" + orderNo + "%", AccountRecordStatusEnum.WAIT.getIndex());
        accountRecordEntities.forEach(accountRecordEntity -> {
            doneTransfer(accountRecordEntity);
//            noticeAccount(accountRecordEntity);
        });
    }


    /**
     * 完成一条未完成记录的转账
     *
     * @param accountRecordEntity
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doneTransfer(AccountRecordEntity accountRecordEntity) {
        BigDecimal amount = accountRecordEntity.getAmount();
        AccountEntity fromUserAccount = decrease(accountRecordEntity.getFromUserId(), accountRecordEntity.getType(), amount);
        AccountEntity toUserAccount = increase(accountRecordEntity.getToUserId(), accountRecordEntity.getType(), amount);
        accountRecordEntity.setFromNowAmount(fromUserAccount.getAmount());
        accountRecordEntity.setToNowAmount(toUserAccount.getAmount());
        accountRecordEntity.setStatus(AccountRecordStatusEnum.DONE.getIndex());
        accountRecordEntity.setTime(new Date());
        accountRecordDao.update(accountRecordEntity);
        //通知
        noticeAccount(accountRecordEntity);
    }

    @Override
    public List<AccountRecordEntity> findByOrderNoAndBusType(String orderNo, Integer... busTypes) {
        return accountRecordDao.findByOrderNoAndBusType(orderNo, busTypes);
    }

    /**
     * 五集注册奖励优惠券 89元
     *
     * @param userId
     */
    @Override
    public void rewardWgRegister(Long userId) {
        AccountRecordEntity recordEntity = buildAwaitTransfer(userId, AccountRecordTypeEnum.COUPON.getIndex(), new BigDecimal(89), "五集注册奖励", AccountRecordBusEnum.TRANSFER.getIndex());
        //立即给与
        doneTransfer(recordEntity);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void transfer(AccountRecordVo recordVo) {
        //验证账户
        UserEntity fromUser = recordVo.getFromUser();
        UserEntity toUser = recordVo.getToUser();
        //验证账户
        userService.validateUser(fromUser, toUser);
        fromUser = userDao.findByCode(fromUser.getCode());
        toUser = userDao.findByCode(toUser.getCode());
        transfer(fromUser.getId(), toUser.getId(), recordVo.getRecord().getType(), recordVo.getRecord().getAmount(), recordVo.getRecord().getInfo());
    }

    @Autowired
    private NoticeService noticeService;

    //通知
    void noticeAccount(AccountRecordEntity recordEntity) {
        setScale(recordEntity);//精确度转换
        String remark = "稍后到账 ";
        if (recordEntity.getStatus().equals(AccountRecordStatusEnum.DONE.getIndex())) {
            remark = "资金变动";
        }
        UserEntity fromUser = userDao.get(recordEntity.getFromUserId());
        if (fromUser != null) {
            noticeService.sendAccount(fromUser.getOpenId(), "-" + recordEntity.getAmount(), recordEntity.getFromNowAmount(), AccountTypeEnum.indexOf(recordEntity.getType()), remark + recordEntity.getInfo());
        }
        UserEntity toUser = userDao.get(recordEntity.getToUserId());
        noticeService.sendAccount(toUser.getOpenId(), "+" + recordEntity.getAmount(), recordEntity.getToNowAmount(), AccountTypeEnum.indexOf(recordEntity.getType()), remark + recordEntity.getInfo());
    }

    private void setScale(AccountRecordEntity recordEntity) {
        BigDecimal amount = recordEntity.getAmount();
        if (amount != null) {
            recordEntity.setAmount(amount.setScale(2, BigDecimal.ROUND_HALF_DOWN));
        }
        BigDecimal fromNowAmount = recordEntity.getFromNowAmount();
        if (fromNowAmount != null) {
            recordEntity.setFromNowAmount(fromNowAmount.setScale(2, BigDecimal.ROUND_HALF_DOWN));
        }
        BigDecimal toNowAmount = recordEntity.getToNowAmount();
        if (toNowAmount != null) {
            recordEntity.setToNowAmount(toNowAmount.setScale(2, BigDecimal.ROUND_HALF_DOWN));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AccountEntity decrease(Long userId, Integer type, BigDecimal amount) {

        AccountEntity accountEntity = findByUserIdAndType(userId, type);
        if (userId.equals(Const.ADMIN_ID)) {

            return accountEntity;
        }
        if (accountEntity.getAmount().compareTo(amount) < 0) {
            throw new RRException("账户余额不足");
        }
        accountDao.decrease(userId, type, amount);
        return accountDao.get(accountEntity.getId());
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public AccountEntity increase(Long userId, Integer type, BigDecimal amount) {
        AccountEntity accountEntity = findByUserIdAndType(userId, type);
        accountDao.increase(userId, type, amount);
        return accountDao.get(accountEntity.getId());
    }

    @Override
    public List<AccountEntity> findByUserId(Long userId) {
        return accountDao.findByUserId(userId);
    }

    @Autowired
    private WxConfigService wxConfigService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AccountRecordEntity payment(Long userId, Long recordId) {
        AccountRecordEntity recordEntity = accountRecordDao.get(recordId);
        if (!recordEntity.getBus().equals(AccountRecordBusEnum.PAYMENT.getIndex()) && !recordEntity.getBus().equals(AccountRecordBusEnum.SHOP.getIndex()) && !recordEntity.getBus().equals(AccountRecordBusEnum.SHOP_MANAGER_REWARD.getIndex()) && !recordEntity.getBus().equals(AccountRecordBusEnum.SHARE_REWARD.getIndex())
                && !recordEntity.getBus().equals(AccountRecordBusEnum.AREA_REWARD.getIndex())&&!recordEntity.getBus().equals(AccountRecordBusEnum.LEVEL_PROFIT.getIndex())) {
            throw new RRException("禁止操作!");
        }

        if (!recordEntity.getToUserId().equals(userId)) {
            throw new RRException("请勿操作他人订单!");
        }

        if (recordEntity.getStatus().equals(AccountRecordStatusEnum.DONE.getIndex())) {
            throw new RRException("已收款,请勿重复收款");
        }

        //获取订单编号
        String orderNo;
        if (recordEntity.getInfo().contains(Const.ORDER_NO)) {
            orderNo = recordEntity.getInfo().split(Const.ORDER_NO)[1];
        } else {
            orderNo = recordEntity.getInfo();
        }

        //货款一个小时后才能收
        if (recordEntity.getBus().equals(AccountRecordBusEnum.PAYMENT.getIndex())||recordEntity.getBus().equals(AccountRecordBusEnum.LEVEL_PROFIT.getIndex())) {
            // 货款一小时后收款
            if (DateUtil.getHours(recordEntity.getTime(), new Date()) < Const.HOUR) {
                throw new RRException("一小时后收款");
            }
            //货款收款必须大于额定业绩
            BigDecimal bigDecimal = teamSaleDao.sumTotalPrice(userId,recordEntity.getTime());
            LevelEntity level = levelDao.get(userDao.get(userId).getLevelId());
            if(bigDecimal.compareTo(level.getSale())<0){
                throw new RRException("需要"+level.getSale()+"团队业绩");
            }
        } else {
            //分享利润 店铺利润七天后才能收
            Long tem = Const.BACK_DAY - DateUtil.getDays(recordEntity.getTime(), new Date());
            //如果是店铺利润
            if(recordEntity.getBus().equals(AccountRecordBusEnum.SHOP.getIndex())){
                MallOrderEntity orderEntity = mallOrderDao.findByOrderNo(orderNo);
                if(orderEntity==null){
                    throw new RRException("订单不存在!");
                }
                if(orderEntity.getDeliverTime()==null){
                    throw new RRException("请发货后收款!");
                }else {
                    tem = Const.BACK_DAY - DateUtil.getDays(orderEntity.getDeliverTime(), new Date());
                }
            }
            //还没有到收款时间
            if (tem > 0) {
                throw new RRException(tem + "天后收款!");
            }

            if(recordEntity.getMonth()!=null){
                Boolean bm = false;
                MallOrderEntity orderEntity = mallOrderDao.findByOrderNo(orderNo);
                 List<OrderItemEntity> list = orderItemDao.findByOrderId(orderEntity.getId());
                 //只有有分享有利润的产品才会限制月销
                 for (OrderItemEntity itemEntity:list){
                     MallGoodsEntity goods = mallGoodsDao.get(itemEntity.getGoodsId());
                     if(goods.getSaleType().equals(MallGoodsSaleTypeEnum.RETAIL.getIndex())){
                         bm = true;
                         break;
                     }
                 }
                //月销限制
                 if(bm){
                     int sum = shareDao.sumQuantity(userId,recordEntity.getTime());
                     if(recordEntity.getMonth()>sum){
                         throw new RRException("请完成"+recordEntity.getMonth()+"单");
                     }
                 }

            }
        }


//        if(recordEntity.getType().equals(AccountTypeEnum.CASH.getIndex())&&recordEntity.getBus().equals(AccountRecordBusEnum.SHARE_REWARD.getIndex())){
//            wxTransfer(recordEntity);
//        }else {
            //完成转账
            doneTransfer(recordEntity);
//        }

        //如果是货款还需要进行一系列操作
        if (recordEntity.getBus().equals(AccountRecordBusEnum.PAYMENT.getIndex())) {
            //订单补货或者还货
            mallOrderService.payment(orderNo,recordEntity.getToUserId());
            //转让平级利润 与 VIP负责人利润
            mallOrderService.equalLevel(userId,orderNo);
            mallOrderService.vipProfit(userId,orderNo);
        }
//        noticeAccount(recordEntity);
        return recordEntity;
    }


    @Override
    public void wxTransfer(AccountRecordEntity recordEntity) {
        //不是代金券与分享有利
        if(!recordEntity.getType().equals(AccountTypeEnum.CASH.getIndex())||!recordEntity.getBus().equals(AccountRecordBusEnum.SHARE_REWARD.getIndex())){
            return;
        }
        //分享有利润 直接到微信红包
        UserEntity user = userDao.get(recordEntity.getToUserId());
        //更新已经发放
        recordEntity.setStatus(AccountRecordStatusEnum.DONE.getIndex());
        accountRecordDao.update(recordEntity);
        //开始发放
        try {
            String certPath = this.getClass().getClassLoader().getResource("apiclient_cert.p12").getPath();
            String serialNo = "1F2EA7A1F956137E3748D294E505A518069623B0";
            SdkResult sdkResult = SdkApi.businessTransfer(certPath,serialNo,recordEntity.getId().toString()
                    ,wxConfigService.getWebConfig().getAppId(),wxConfigService.getWebConfig().getMchId(),user.getOpenId(),user.getCode(),user.getCode(),recordEntity.getAmount());
            if(!sdkResult.isSuccess()){
                throw new RRException("红包错误:"+sdkResult.getError());
            }
        } catch (Exception e) {
            throw new RRException("红包未知错误:"+e.getMessage());
        }
    }

    @Autowired
    private MonthShareDao shareDao;

    @Autowired
    private TeamSaleDao teamSaleDao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String commit(Long userId, BigDecimal amount, String noticeUrl) {
        UserEntity userEntity = userDao.get(userId);
        String orderNo = UUID.randomUUID().toString().replace("-", "");
        AccountRecordEntity recordEntity = new AccountRecordEntity(Const.ADMIN_ID, userId, AccountTypeEnum.CASH.getIndex(), amount, null, null, new Date(), orderNo, AccountRecordStatusEnum.WAIT.getIndex(), AccountRecordBusEnum.CHARGE.getIndex());
        accountRecordDao.save(recordEntity);
        String payConfig = wxPayService.createWebConfig(recordEntity.getInfo(), amount.doubleValue(), "充值", userEntity.getOpenId(), noticeUrl);
        return payConfig;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void recharge(String orderNo, Integer amount) {
        AccountRecordEntity recordEntity = accountRecordDao.findByOrderNo(orderNo);
        //如果已经完成
        if (recordEntity.getStatus().equals(AccountRecordStatusEnum.DONE.getIndex())) {
            return;
        }
        //付款金额正确
        if (recordEntity.getAmount().compareTo(new BigDecimal(amount / 100)) >= 0) {
            AccountEntity accountEntity = findByUserIdAndType(recordEntity.getToUserId(), recordEntity.getType());
            //转账
            increase(accountEntity.getUserId(), recordEntity.getType(), recordEntity.getAmount());
            recordEntity.setStatus(AccountRecordStatusEnum.DONE.getIndex());
            recordEntity.setToNowAmount(accountEntity.getAmount().add(recordEntity.getAmount()));
            accountRecordDao.update(recordEntity);
            //通知
            noticeAccount(recordEntity);
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AccountEntity findByUserIdAndType(Long userId, Integer type) {
        AccountEntity accountEntity = accountDao.findByUserIdAndType(userId, type);
        if (accountEntity == null) {
            accountEntity = new AccountEntity(type, userId, BigDecimal.ZERO, BigDecimal.ZERO);
            accountDao.save(accountEntity);
        }
        return accountEntity;
    }

    @Autowired
    private LevelDao levelDao;

    @Autowired
    private OrderItemDao orderItemDao;

    @Autowired
    private MallActDao mallActDao;

    @Autowired
    private MallOrderDao mallOrderDao;


    /**
     * Long
     * 根据用户去查询佣金的明细
     *
     * @param userId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<OrderItemVo> findCommission(Long userId, Integer year, Integer month) {
//      获取账号记录信息 TODO
        List<Integer> types = new ArrayList<>();
        List<AccountRecordVo> accountRecordVos = this.accountRecordDao.queryByToUserId(userId, Const.ADMIN_ID, AccountTypeEnum.CASH.getIndex(), AccountRecordStatusEnum.DONE.getIndex(), year, month, "%" + Const.ORDER_NO + "%", AccountRecordBusEnum.SHARE_REWARD.getIndex());
        List<AccountRecordVo> accountRecordVoss = this.accountRecordDao.queryByToUserId(userId, Const.ADMIN_ID, AccountTypeEnum.CASH.getIndex(), AccountRecordStatusEnum.DONE.getIndex(), year, month, "%" + Const.ORDER_NO + "%", AccountRecordBusEnum.AREA_REWARD.getIndex());
        List<AccountRecordVo> accountRecordVoList = this.accountRecordDao.queryByToUserId(userId, Const.ADMIN_ID, AccountTypeEnum.CASH.getIndex(), AccountRecordStatusEnum.DONE.getIndex(), year, month, "%" + Const.REWARD_TRANSFER + "%", AccountRecordBusEnum.TRANSFER.getIndex());
        accountRecordVos.addAll(accountRecordVoList);
        accountRecordVos.addAll(accountRecordVoss);
        List<OrderItemVo> orderItemVoList = new ArrayList<>();
        accountRecordVos.forEach(accountRecordVo -> {

            String accountInfo = accountRecordVo.getRecord().getInfo();
            String orderNo = accountInfo;
            if (accountInfo.equals("") || accountInfo == null) {
                return;
            }

            if (accountInfo.contains(Const.TRANSFER_REWARD)) {
                orderNo = accountInfo.split(Const.TRANSFER_REWARD)[1];
            }
            if (accountInfo.contains(Const.TRANSFER_ORDER_NO)) {
                orderNo = accountInfo.split(Const.TRANSFER_ORDER_NO)[1];
            }
            if (accountInfo.contains(Const.ORDER_NO)) {
                orderNo = accountInfo.split(Const.ORDER_NO)[1];
            }

            List<AccountRecordEntity> accountRecordEntities = this.accountRecordDao.findByOrderNos("%" + orderNo + "%", AccountRecordStatusEnum.DONE.getIndex());
            for (AccountRecordEntity accountRecordEntity : accountRecordEntities) {
                if (accountRecordEntity.getBus() == AccountRecordBusEnum.BACK.getIndex()) {
                    return;
                }
            }
            List<OrderItemVo> orderItemVos = this.orderItemDao.findByOrderNo(orderNo);
            orderItemVos.forEach(orderItemVo -> {
                if (orderItemVo != null) {
                    UserEntity userEntity = this.userDao.get(orderItemVo.getUserId());
                    orderItemVo.setName(userEntity.getName());
                    orderItemVo.setGoodsName(orderItemVo.getGoodsName() + "*" + orderItemVo.getQuantity());
                    orderItemVo.setIncome(accountRecordVo.getRecord().getAmount());
                    if (null != accountRecordVo.getRecord().getTime()) {
                        SimpleDateFormat sdf = new SimpleDateFormat("MM/dd");
                        String format = sdf.format(accountRecordVo.getRecord().getTime());
                        orderItemVo.setTime(format);
                    }


                    orderItemVo.setRemark(accountRecordVo.getRecord().getInfo());

                    orderItemVoList.add(orderItemVo);
                }
            });

        });

        return orderItemVoList;
    }

    @Autowired
    private WxPayService wxPayService;

    /**
     * Long
     * 用户编号，类型，数量，备注
     * 后台批量转卷
     *
     * @param inputStream
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void upload(InputStream inputStream) {
        EasyExcel.read(inputStream, AccountUpVo.class, new UploadDataListener()).sheet().doRead();
    }

    class UploadDataListener extends AnalysisEventListener<AccountUpVo> {


        @Override
        @Transactional(rollbackFor = Exception.class)
        public void invoke(AccountUpVo accountUpVo, AnalysisContext analysisContext) {

            UserEntity userEntity = userDao.findByCode(accountUpVo.getCode());
            if (userEntity == null) {
                return;
            }
            if (accountUpVo.getType() == null) {
                accountUpVo.setType(AccountTypeEnum.COUPON.getIndex());
            }
            // 转卷
            transfer(Const.ADMIN_ID, userEntity.getId(), accountUpVo.getType(), accountUpVo.getNumber(), accountUpVo.getRemark());
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {

        }

    }


}

